/*
 * @Author: 生俊甫 1758142861@qq.com
 * @Date: 2024-06-06 17:40:25
 * @LastEditors: 生俊甫 1758142861@qq.com
 * @LastEditTime: 2024-06-17 20:40:30
 * @FilePath: /sjf/2024-project/2024_centos/source/db/db.hpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#pragma once

#include <iostream>
#include <cassert>
#include <mutex>
#include "../util.hpp"
#include <mysql/mysql.h>
#include "../log/log.hpp"


/**
 * id username password score total_count win_count
 * 注册
 * 登录
 * 通过用户id查询用户信息
 * 通过用户名查询用户信息
 * 胜利相关(score+30,total_count+1,win_count+1)
 * 失败相关(score-30,total_count+1)
 */
class user_table
{
public:
    user_table(
        const std::string host,
        const std::string username,
        const std::string password,
        const std::string dbname,
        const unsigned int port = 3306
    )
    {
        _mysql = util_mysql::mysql_create(host, username, password, dbname, port);
        assert(_mysql);
    }
    ~user_table()
    {
        util_mysql::mysql_destory(_mysql);
    }
    //注册
    bool user_register(Json::Value& user)
    {
#define INSERT_USER "insert into user (username,password,score,total_count,win_count) value ('%s',password('%s'),1000,0,0);"
        if(user["username"].isNull() || user["password"].isNull())
        {
            ERR_LOG("user_register input password or username!");
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql,INSERT_USER,user["username"].asCString(),user["password"].asCString());
        if(util_mysql::mysql_exec(_mysql,sql) == false)
        {
            ERR_LOG("user_register mysql insert sql err!");
            return false;
        }
        return true;
    }
    //登录,user输出型参数
    bool user_login(Json::Value& user)
    {
        if(user["username"].isNull() || user["password"].isNull())
        {
            ERR_LOG("user_login input password or username!");
            return false; 
        }
#define LOGIN_USER "select id,score,total_count,win_count from user where username = '%s' and password = password('%s');"
        char sql[4096] = {0};
        sprintf(sql,LOGIN_USER,user["username"].asCString(),user["password"].asCString());
        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(util_mysql::mysql_exec(_mysql,sql) == false)
            {
                ERR_LOG("user_login mysql insert sql err!");
                return false;
            }
            // 按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            //将结果保存至本地
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ERR_LOG("user_login mysql insert sql err!");
                return false;
            }
        }
        //获取查询结果的数量，我们根据name查询只能有一条，因为用户名不能重复
        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            ERR_LOG("the user information queried is not unique!!\n");
            return false;
        }
        //取出该条数据
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        //删除本地数据
        DBG_LOG("user login sueecss!");
        mysql_free_result(res);
        return true;
    }
    //通过用户id查询用户信息
    bool select_user_by_id(const int id,Json::Value& user)
    {
#define USER_BY_ID "select id,username,score,total_count,win_count from user where id = '%d';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_ID,id);
        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = util_mysql::mysql_exec(_mysql,sql);
            if (ret == false)
            {
                ERR_LOG("get user by id failed!!\n");
                return false;
            }
            // 按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            //将结果保存至本地
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ERR_LOG("user_login mysql insert sql err!");
                return false;
            }
        }
        //获取查询结果的数量，我们根据name查询只能有一条，因为用户名不能重复
        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            ERR_LOG("the user information queried is not unique!!\n");
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)id;
        user["username"] = row[1];
        user["score"] = (Json::UInt64)std::stol(row[2]);
        user["total_count"] = std::stoi(row[3]);
        user["win_count"] = std::stoi(row[4]);
        mysql_free_result(res);
        return true;
    }
    //通过用户名查询用户信息
    bool select_user_by_name(const std::string& name,Json::Value& user)
    {
#define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s';"
        char sql[4096] = {0};
        sprintf(sql,USER_BY_NAME,name.c_str());
        MYSQL_RES* res = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = util_mysql::mysql_exec(_mysql,sql);
            if (ret == false)
            {
                ERR_LOG("get user by name failed!!\n");
                return false;
            }
            // 按理说要么有数据，要么没有数据，就算有数据也只能有⼀条数据
            //将结果保存至本地
            res = mysql_store_result(_mysql);
            if(res == nullptr)
            {
                ERR_LOG("user_login mysql insert sql err!");
                return false;
            }
        }
        //获取查询结果的数量，我们根据name查询只能有一条，因为用户名不能重复
        int row_num = mysql_num_rows(res);
        if(row_num != 1)
        {
            ERR_LOG("the user information queried is not unique!!\n");
            return false;
        }
        //取出该条数据
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["username"] = name;
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
    //胜利
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score = score + 30, total_count = total_count + 1,win_count = win_count + 1 where id = %d;"
        char sql[4096] = {0};
        sprintf(sql,USER_WIN,id);
        bool ret = util_mysql::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            ERR_LOG("update user win info failed!\n");
            return false;
        }
        return true;
    }
    // 失败机制(天体分数减少30分，场次+1)
    bool lose(uint64_t id)
    {
#define USER_LOST "update user set score = score - 30, total_count = total_count + 1 where id = %d;"
        char sql[4096] = {0};
        sprintf(sql, USER_LOST, id);
        bool ret = util_mysql::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            ERR_LOG("update use lose info failed!\n");
            return false;
        }
        return true;
    }
private:
    MYSQL* _mysql;
    std::mutex _mutex;
};